﻿using System;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Jack.DataScience.Common;
using Jack.DataScience.Http.Jwt;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Converters;
using Swashbuckle.AspNetCore.Swagger;
using Autofac.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Vav.Data.MySQL;
using Vav.Data.DataAccess;
using Vav.Data.OSS;
using Vav.Api.Utils;
using Autofac;
using Jack.DataScience.Data.Converters;
using Jack.DataScience.Data.MongoDB;
using Jack.DataScience.Data.JsonConverters;

namespace Vav.Api
{
    public class Startup
    {
        public static IContainer ApplicationContainer { get; private set; }

        public const string CorsPolicy = "Cors";
        public const string SwaggerApiName = "CarPool_API";
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }


        /// <summary>
        /// all controller and data access setups should go to here
        /// </summary>
        /// <param name="env"></param>
        /// <param name="includedControllers">当用单元测试生成Autofac时，需要注册所有Controller，此值应为true</param>
        /// <returns></returns>
        public  ContainerBuilder SetupBuilder()
        {
            AutoFacContainer autoFacContainer = new AutoFacContainer(Configuration);

            autoFacContainer.RegisterOptions<VavdbDataOptions>();
            autoFacContainer.RegisterOptions<MongoOptions>();
            autoFacContainer.RegisterOptions<OssOptions>();

            autoFacContainer.RegisterOptions<AuthOptions>();
            autoFacContainer.RegisterOptions<JwtSecretOptions>();
            autoFacContainer.RegisterOptions<SecurityEncryptionOptions>();

            autoFacContainer.ContainerBuilder.RegisterModule<JwtModule>();
            autoFacContainer.ContainerBuilder.RegisterModule<MongoModule>();
            autoFacContainer.ContainerBuilder.RegisterModule<VavdbDataModule>();
            autoFacContainer.ContainerBuilder.RegisterModule<ConvertersModule>();
            autoFacContainer.ContainerBuilder.RegisterModule<DataAccessModule>();
            autoFacContainer.ContainerBuilder.RegisterModule<OssModule>();
            return autoFacContainer.ContainerBuilder;
        }

        // This method gets called by the runtime. Use this method to add services to the container.
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
                .AddJsonOptions(options =>
                {
                    //设置时间格式
                    options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                });

            ContainerBuilder builder = SetupBuilder();

            // set up GenericJwtToken access via dependency injection
            builder.Register(context =>
            {
                var httpContextAccessor = context.Resolve<IHttpContextAccessor>();
                return httpContextAccessor.HttpContext.Request.ReadJWTCookie();
            });

            builder.RegisterType<RoleJwtEncoder>();
            services.AddMemoryCache();
            services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

            services.AddCors(options =>
                    options.AddPolicy(
                        CorsPolicy,
                        corsBuilder =>
                            corsBuilder
                                .SetIsOriginAllowed(url =>true)
                                .AllowAnyMethod()
                                .AllowAnyHeader()
                                .AllowCredentials()
                        )
                );

            services.AddMvc().AddJsonOptions(json =>
            {
                json.SerializerSettings.Error = OnJsonError;
                //json.SerializerSettings.ContractResolver = new DefaultContractResolver();
                json.SerializerSettings.Converters.Add(new StringEnumConverter());
                json.SerializerSettings.Converters.Add(new BsonDocumentConverter());
            });

            services.AddSwaggerGen(
                setup =>
                    setup.SwaggerDoc(SwaggerApiName,
                    new Info
                    {
                        Version = "1",
                        Title = "MediGraph API Server",
                        Description = "MediGraph API",
                        TermsOfService = "N/A"
                    })
                );

            builder.Populate(services);
            ApplicationContainer = builder.Build();
            return new AutofacServiceProvider(ApplicationContainer);
        }

        public void OnJsonError(object source, ErrorEventArgs error)
        {
            Debugger.Break();
        }


        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsProduction())
                app.UseExceptionHandler(GlobalException.ExceptionHandler);
            else
                app.UseDeveloperExceptionPage();
            app.UseCors(CorsPolicy);
            // app.UseHttpsRedirection();
            app.UseMvc();

            app.UseSwagger();
            app.UseSwaggerUI(setup => setup.SwaggerEndpoint($"/swagger/{SwaggerApiName}/swagger.json", "MediGraph API"));
            app.UseMvc(routes =>
            {
                routes.MapSpaFallbackRoute("spaFallback", new { controller = "Home", action = "Spa" });
            });
        }
    }
}
